const express = require("express");
const fs = require("fs");


const cfile = {};

// 目录 directory


/**
 * 将文件移动至用新文件夹 如果文件夹不存则在指定路径建立相应文件
 * @param   {String}  oldFilepath 旧文件路径 .../file.ext
 * @param   {String}  newFiledir  新文件目录 .../
 * @returns {Promise}
 **/
cfile.moveFile = async (oldFilepath, newFiledir, callback) => {

    let file_name_a = oldFilepath.substring(oldFilepath.lastIndexOf("/"))
    let file_name_b = oldFilepath.substring(oldFilepath.lastIndexOf("\\"))
    let file_name = (file_name_a === file_name_a ? file_name_b : file_name_a)

    new_FilePath = newFiledir + file_name

    return new Promise((resolve, reject) => {
        // 当用户目录不存在时创建新的用户目录
        if (!fs.existsSync(newFiledir)) {
            fs.mkdir(newFiledir, (_err) => {
                if (_err) {
                    return reject(_err);
                } else {
                    resolve()
                }
            })
        } else {
            resolve()
        }

    }).then(() => {
        // 移动文件
        new Promise((resolve, reject) => {
            fs.rename(oldFilepath, new_FilePath, (_err) => {
                if (_err) {
                    return reject(_err);
                } else {
                    callback()
                    return resolve()
                }
            })
        }).catch((_err) => {
            callback(_err)
            return;
        })

    }).catch((_err) => {
        callback(_err)
        return;
    })
}


/**
 * 文件异步合并
 * @param   {String}  chunkPath   将要合并的分片文件目录 .../chunks id/
 * @param   {String}  newFilename 合并所得到的新文件名称 filename.ext
 * @param   {Number}  total       分片文件总数
 * @returns {Promise}
 **/
cfile.mergeFile = async (chunkPath, newFilename, total, callback) => {
    // 获取路径
    let file_ext = newFilename.substring(newFilename.lastIndexOf("."))
    let before_chunkPath_a = chunkPath.substring(0, chunkPath.lastIndexOf("\\"));
    let before_chunkPath_b = chunkPath.substring(0, chunkPath.lastIndexOf("/"));
    let before_chunkPath = before_chunkPath_a === null ? before_chunkPath_b : before_chunkPath_a
    let new_filepath = before_chunkPath + "\\" + newFilename

    return new Promise((resolve, reject) => {
        // 获取切片目录
        fs.readdir(chunkPath, (_err, _files) => {

            if (_err) {
                return reject(_err)
            }
            if (_files.length != total || !_files.length) {
                return reject(`上传失败 切片数量不符${_files.length}`)
            }

            let rel_ext = _files[0].substring(_files[0].lastIndexOf("."))
            if (rel_ext !== file_ext) {
                return reject("上传失败 文件名错误")
            }
            // 创建写入文件
            const fileWriteStream = fs.createWriteStream(new_filepath)

            // 递归合并函数
            function _merge(chunk_num) {

                let chunk_name = chunkPath + "/" + chunk_num + file_ext;

                return new Promise((resolve, reject) => {
                    if (chunk_num === _files.length) {
                        // 删除合并文件夹
                        fs.rmdir(chunkPath, (_err) => {
                            return reject(_err)
                        })
                        return resolve()
                    }
                    // 读取文件块
                    fs.readFile(chunk_name, (_err, _data) => {
                        if (_err) {
                            return reject(_err)
                        }
                        // 将切片追加到存储文件
                        fs.appendFile(new_filepath, _data, () => {
                            // 删除切片文件
                            fs.unlink(chunk_name, () => {
                                // 递归合并
                                resolve(_merge(chunk_num + 1))
                            })
                        })
                    })
                }).catch((_err) => {
                    callback(_err)
                    return _err;
                })
            }

            // 掉用递归
            _merge(0).then(() => {
                // 关闭可写流
                fileWriteStream.close()
                callback()
                resolve()
            })
        })
    }).catch((_err) => {
        callback(_err)
        return _err;
    })
}


/**
 * 切片异步合并 从文件夹中提取合并切片至上一级
 * @param   {String}  chunkPath   将要合并的分片文件目录 .../chunks id/
 * @param   {String}  chunkFlag   文件标签 用与区分文件
 * @param   {String}  newFileFlag 合并所得到的新文件名称 filename.ext
 * @param   {Number}  total       分片文件总数
 * @returns {Promise}
 **/
cfile.mergeFiles = async (chunkPath, chunkFlag, newFileFlag, total, callback) => {
    // 获取路径
    let before_chunkPath_a = chunkPath.substring(0, chunkPath.lastIndexOf("\\"));
    let before_chunkPath_b = chunkPath.substring(0, chunkPath.lastIndexOf("/"));
    let before_chunkPath = before_chunkPath_a === null ? before_chunkPath_b : before_chunkPath_a

    return new Promise((resolve, reject) => {
        // 获取切片目录
        fs.readdir(chunkPath, (_err, files) => {
            // 返回对应文件数组
            let _files = []
            if (_err) {
                return reject(_err)
            }
            for (f of files) {
                if (f.indexOf(chunkFlag) > -1) {
                    _files.push(f)
                }
            }
            if (_files.length + "" != total) {
                return reject(`上传失败 切片数量不符${_files.length}`)
            } else if (!_files.length) {
                callback()
                return ;
            }
            let rel_ext = _files[0].substring(_files[0].lastIndexOf("."))
            // 创建写入文件
            let new_filepath = before_chunkPath + "\\" + newFileFlag + rel_ext
            const fileWriteStream = fs.createWriteStream(new_filepath)

            // 递归合并函数
            function _merge(chunk_num) {

                let chunk_name = chunkPath + "/" + chunk_num + "-" + chunkFlag + rel_ext;

                return new Promise((resolve, reject) => {
                    if (chunk_num === _files.length) {
                        // 删除合并文件夹
                        return resolve()
                    }
                    // 读取文件块
                    fs.readFile(chunk_name, (_err, _data) => {
                        if (_err) {
                            return reject(_err)
                        }
                        // 将切片追加到存储文件
                        fs.appendFile(new_filepath, _data, () => {
                            // 删除切片文件
                            fs.unlink(chunk_name, () => {
                                // 递归合并
                                resolve(_merge(chunk_num + 1))
                            })
                        })
                    })
                }).catch((_err) => {
                    callback(_err)
                    return _err;
                })
            }

            // 掉用递归
            _merge(0).then(() => {
                // 关闭可写流
                fileWriteStream.close()
                let _err = null;
                callback(_err, rel_ext)
                resolve()
            })
        })
    }).catch((_err) => {
        callback(_err)
        return _err;
    })

}


/**
 * 切片异步合并转移 从文件夹中提取合并转移到指定目录
 * @param   {String}  chunkPath   将要合并的分片文件目录 .../chunks id/
 * @param   {String}  chunkFlag   文件标签 用与区分文件
 * @param   {String}  newFileFlag 合并所得到的新文件名称 filename.ext
 * @param   {Number}  total       分片文件总数
 * @returns {Promise}
 **/
 cfile.mergeFilesChange = async (chunkPath, chunkFlag, newFilePath, newFileFlag, total, callback) => {
    return new Promise((resolve, reject) => {
        // 获取切片目录
        fs.readdir(chunkPath, (_err, files) => {
            // 返回对应文件数组
            let _files = []
            if (_err) {
                return reject(_err)
            }
            for (f of files) {
                if (f.indexOf(chunkFlag) > -1) {
                    _files.push(f)
                }
            }
            if (_files.length + "" != total) {
                return reject(`上传失败 切片数量不符${_files.length}`)
            } else if (!_files.length) {
                callback()
                return ;
            }
            let rel_ext = _files[0].substring(_files[0].lastIndexOf("."))
            // 创建写入文件
            let new_filepath = newFilePath + "\\" + newFileFlag + rel_ext
            const fileWriteStream = fs.createWriteStream(new_filepath)

            // 递归合并函数
            function _merge(chunk_num) {

                let chunk_name = chunkPath + "/" + chunk_num + "-" + chunkFlag + rel_ext;

                return new Promise((resolve, reject) => {
                    if (chunk_num === _files.length) {
                        // 删除合并文件夹
                        return resolve()
                    }
                    // 读取文件块
                    fs.readFile(chunk_name, (_err, _data) => {
                        if (_err) {
                            return reject(_err)
                        }
                        // 将切片追加到存储文件
                        fs.appendFile(new_filepath, _data, () => {
                            // 删除切片文件
                            fs.unlink(chunk_name, () => {
                                // 递归合并
                                resolve(_merge(chunk_num + 1))
                            })
                        })
                    })
                }).catch((_err) => {
                    callback(_err)
                    return _err;
                })
            }

            // 掉用递归
            _merge(0).then(() => {
                // 关闭可写流
                fileWriteStream.close()
                let _err = null;
                callback(_err, rel_ext)
                resolve()
            })
        })
    }).catch((_err) => {
        callback(_err)
        return _err;
    })

}


/**
 * 返回文件和文件夹
 * @param {String} file_path
 * @param {Function} callback
 * @returns {Promise}
 **/
cfile.getFiles = async (file_path, callback) => {
    return new Promise((resolve, reject) => {

        fs.readdir(file_path, (_err, files) => {
            if (_err){
                reject(_err)
            } else {
                callback(_err, files)
                return resolve();
            }
        })
    }).catch ((err) => {
        callback(err)
        return err;
    })
}


cfile.deleteFile = async (file_path) => {
    return new Promise((resolve, reject) => {

        fs.unlink(file_path, (err) => {
            if (err) {
                reject(err)
            } else {
                resolve()
            }
        })
    })
}


module.exports = { cfile }
